package com.googlecode.agscrum.controller.jsf.bean;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.model.SelectItem;

import org.richfaces.component.Dropzone;
import org.richfaces.component.UITree;
import org.richfaces.event.DropEvent;
import org.richfaces.event.NodeSelectedEvent;
import org.richfaces.model.TreeNode;
import org.richfaces.model.TreeNodeImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;

import com.googlecode.agscrum.controller.jsf.util.FacesUtil;
import com.googlecode.agscrum.controller.jsf.wrapper.SprintWrapper;
import com.googlecode.agscrum.controller.spring.MyIdentity;
import com.googlecode.agscrum.model.entity.Item;
import com.googlecode.agscrum.model.entity.Product;
import com.googlecode.agscrum.model.entity.Sprint;
import com.googlecode.agscrum.model.entity.Task;
import com.googlecode.agscrum.model.entity.Team;
import com.googlecode.agscrum.model.entity.User;
import com.googlecode.agscrum.model.exceptions.GScrumDomainException;
import com.googlecode.agscrum.model.service.Service;
import com.googlecode.agscrum.model.util.Criteria;

@Controller("itemControllerBean")
@Scope("request")
public class ItemControllerBean {
	@Autowired
	@Qualifier(value = "productService")
	private Service<Product, Long> productService;

	public void setProductService(Service<Product, Long> productService) {
		this.productService = productService;
	}

	@Autowired
	@Qualifier(value = "myIdentity")
	private MyIdentity myIdentity;

	public void setMyIdentity(MyIdentity myIdentity) {
		this.myIdentity = myIdentity;
	}

	@Autowired
	@Qualifier(value = "teamService")
	private Service<Team, Long> teamService;

	public void setTeamService(Service<Team, Long> teamService) {
		this.teamService = teamService;
	}

	private Product product;

	@PostConstruct
	public void init() {
		product = productService.findById(myIdentity.getProduct().getId());
	}

	private TreeNode<Item> rootNodeItems;

	@SuppressWarnings("unchecked")
	public TreeNode getTreeNodeItems() {
		loadTreeItems();
		return rootNodeItems;
	}

	private void loadTreeItems() {
		rootNodeItems = new TreeNodeImpl<Item>();
		int i = 0;
		for (Item item : product.getItems()) {
			if (item.getSprint() == null) {
				TreeNodeImpl<Item> nodeImpl = new TreeNodeImpl<Item>();
				nodeImpl.setData(item);
				rootNodeItems.addChild(i++, nodeImpl);
			}
		}
	}

	private TreeNode<SprintWrapper> rootNodeItemsSprint;

	@SuppressWarnings("unchecked")
	public TreeNode getTreeNodeItemsSprint() {
		loadTreeItemsSprint();
		return rootNodeItemsSprint;
	}

	private void loadTreeItemsSprint() {
		rootNodeItemsSprint = new TreeNodeImpl<SprintWrapper>();
		int i = 0;
		for (Sprint sprint : product.getSprints()) {
			TreeNodeImpl<SprintWrapper> nodeImpl = new TreeNodeImpl<SprintWrapper>();
			nodeImpl.setData(new SprintWrapper(sprint));
			addItems(nodeImpl, sprint);
			rootNodeItemsSprint.addChild(i++, nodeImpl);
		}
	}

	private void addItems(TreeNodeImpl<SprintWrapper> nodeImpl, Sprint sprint2) {
		int i = 0;
		if (sprint2.getItems() != null) {
			for (Item item : sprint2.getItems()) {
				TreeNodeImpl<SprintWrapper> nodeImplItem = new TreeNodeImpl<SprintWrapper>();
				nodeImplItem.setData(new SprintWrapper(item));
				addTasks(nodeImplItem, item);
				nodeImpl.addChild(i++, nodeImplItem);
			}
		}
	}

	private void addTasks(TreeNodeImpl<SprintWrapper> nodeImplItem, Item item2) {
		int i = 0;
		if (item2.getTasks() != null) {
			for (Task task : item2.getTasks()) {
				TreeNodeImpl<SprintWrapper> nodeImplTask = new TreeNodeImpl<SprintWrapper>();
				nodeImplTask.setData(new SprintWrapper(task));
				nodeImplItem.addChild(i++, nodeImplTask);
			}
		}
	}

	private Item item = new Item();
	private Sprint sprint = new Sprint();

	public void saveItem() {
		try {
			product.saveItem(item);
			item.setProduct(product);
			if (item.getSprint() != null) {
				item.setEstimate(100);
				item.getSprint().saveItem(item);
			}
			product = productService.save(product);
			item = new Item();
			UITree htmlTree = (UITree) FacesUtil
					.findComponentInRoot("treeSprint");
			htmlTree.setSelected();
		} catch (GScrumDomainException e) {
			FacesUtil.addMessage(e);
		}
	}

	public void saveSprint() {
		try {
			product.saveSprint(sprint);
			sprint.setProduct(product);
			product = productService.save(product);
			sprint = new Sprint();
		} catch (GScrumDomainException e) {
			FacesUtil.addMessage(e);
		}
	}

	public void setItem(Item item) {
		this.item = item;
	}

	public Item getItem() {
		return item;
	}

	public void setSprint(Sprint sprint) {
		this.sprint = sprint;
	}

	public Sprint getSprint() {
		return sprint;
	}

	public List<SelectItem> getTeams() {
		Criteria criteria = Criteria
				.getInstance("Team.searchQuery", Team.class);
		criteria.setCacheable(true);
		List<Team> teams = teamService.readByCriteria(criteria);
		List<SelectItem> itemsTeam = new ArrayList<SelectItem>();
		for (Team team : teams) {
			itemsTeam.add(new SelectItem(team, team.getName()));
		}
		return itemsTeam;
	}

	public List<SelectItem> getUsers() {
		List<SelectItem> itemsUser = new ArrayList<SelectItem>();
		if (itemSprintSelected instanceof SprintWrapper) {
			Team team = null;
			if (((SprintWrapper) itemSprintSelected).getObject() instanceof Item) {
				Item item = (Item) ((SprintWrapper) itemSprintSelected)
						.getObject();
				team = item.getSprint().getTeam();
			} else if (((SprintWrapper) itemSprintSelected).getObject() instanceof Task) {
				Task task = (Task) ((SprintWrapper) itemSprintSelected)
						.getObject();
				team = task.getItem().getSprint().getTeam();
			}
			if (team != null) {
				team = teamService.findById(team.getId());
				for (User user : team.getUsers()) {
					itemsUser.add(new SelectItem(user, user.getName()));
				}
			}
		}
		return itemsUser;
	}

	private Object itemSprintSelected;

	public boolean isTaskSelected() {
		if (itemSprintSelected instanceof SprintWrapper
				&& ((SprintWrapper) itemSprintSelected).getObject() instanceof Task) {
			return true;
		}
		return false;
	}

	public boolean isItemSelected() {
		if (itemSprintSelected instanceof SprintWrapper
				&& ((SprintWrapper) itemSprintSelected).getObject() instanceof Item) {
			return true;
		}
		return false;
	}

	public void processSelection(NodeSelectedEvent event) {
		UITree tree = (UITree) event.getComponent();
		itemSprintSelected = tree.getRowData();
	}

	private Task task = new Task();

	public void saveTask() {
		try {
			Item item = null;
			if (task.getItem() != null) {
				item = task.getItem();
			} else {
				if (itemSprintSelected instanceof SprintWrapper
						&& ((SprintWrapper) itemSprintSelected).getObject() instanceof Item) {
					item = (Item) ((SprintWrapper) itemSprintSelected)
							.getObject();

				}
			}
			item.saveTask(getTask());
			product = productService.save(product);
			setTask(new Task());
		} catch (GScrumDomainException e) {
			FacesUtil.addMessage(e);
		}
	}

	public void setTask(Task task) {
		this.task = task;
	}

	public Task getTask() {
		return task;
	}

	public void dropListener(DropEvent dropEvent) {
		try {
			Dropzone dropzone = (Dropzone) dropEvent.getComponent();
			if (((SprintWrapper) dropzone.getDropValue()).getObject() instanceof Sprint) {
				Sprint sprint = (Sprint) ((SprintWrapper) dropzone
						.getDropValue()).getObject();
				sprint.saveItem((Item) dropEvent.getDragValue());
				product = productService.save(product);
			}
		} catch (GScrumDomainException e) {
			FacesUtil.addMessage(e);
		}
	}

	public void processDrop(DropEvent dropEvent) {
		try {
			if (dropEvent.getDragValue() instanceof SprintWrapper) {
				Item item = (Item) ((SprintWrapper) dropEvent.getDragValue()).getObject();
				Sprint sprint = item.getSprint();
				sprint.removeItem(item);
				product = productService.save(product);
			}
		} catch (GScrumDomainException e) {
			FacesUtil.addMessage(e);
		}
	}

	public void sprintSelection() {
		sprint = (Sprint) ((SprintWrapper) itemSprintSelected).getObject();
	}

	public void removeSprint() {
		Sprint sprint = (Sprint) ((SprintWrapper) itemSprintSelected)
				.getObject();
		try {
			product.removeSprint(sprint);
			product = productService.save(product);
		} catch (GScrumDomainException e) {
			FacesUtil.addMessage(e);
		}
	}

	public void removeTask() {
		Task task = (Task) ((SprintWrapper) itemSprintSelected).getObject();
		try {
			Item item = null;
			if (task.getItem() != null) {
				item = task.getItem();
			}
			if (item != null) {
				item.removeTask(task);
				product = productService.save(product);
			}
		} catch (GScrumDomainException e) {
			FacesUtil.addMessage(e);
		}
	}

	public void itemSprintSelection() {
		Sprint sprint = (Sprint) ((SprintWrapper) itemSprintSelected)
				.getObject();
		item.setSprint(sprint);
	}

	public void itemSelection() {
		item = (Item) ((SprintWrapper) itemSprintSelected).getObject();
	}

	public void taskSelection() {
		task = (Task) ((SprintWrapper) itemSprintSelected).getObject();
	}
}
